package com.sugon.modules.analyse.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.dao.*;
import com.sugon.entity.DevParameterEntity;
import com.sugon.entity.DeviceInfoEntity;
import com.sugon.entity.SysDeptEntity;
import com.sugon.entity.dto.WorkloadStatDTO;
import com.sugon.modules.analyse.consts.DevStatus;
import com.sugon.modules.analyse.consts.FaultHandleTime;
import com.sugon.modules.analyse.model.BarChartOptionModel;
import com.sugon.modules.analyse.model.BarChartSeriesModel;
import com.sugon.modules.analyse.model.chart.LineOptionVisualMapPiecesItemVO;
import com.sugon.modules.analyse.model.chart.PieChartOptionDataVO;
import com.sugon.modules.analyse.model.chart.PieChartSeriesDataItemVO;
import com.sugon.modules.analyse.model.dto.DevAlarmTimeTopStatItemDTO;
import com.sugon.modules.analyse.model.vo.*;
import com.sugon.modules.analyse.service.IDeviceAnalyseService;
import com.sugon.modules.device.consts.DevMaintenanceItemExecuteStatus;
import com.sugon.modules.device.consts.DevMaintenanceTicketStatus;
import com.sugon.modules.device.consts.DevRepairTicketStage;
import com.sugon.modules.device.consts.enums.DevMaintenanceTicketStatusEnum;
import com.sugon.modules.device.consts.enums.DevRepairTicketStatusEnum;
import com.sugon.service.DevParameterService;
import com.sugon.service.DeviceInfoService;
import com.sugon.service.SysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 设备分析统计Service
 * @author: YuXD
 * @create: 2020-05-10 19:56
 **/
@Service
public class DeviceAnalyseServiceImpl implements IDeviceAnalyseService {

    @Autowired
    private DevAlarmRecordDao devAlarmRecordDao;
    @Autowired
    private DevStatusRecordDao devStatusRecordDao;
    @Autowired
    private DevMaintenWorkDao devMaintenWorkDao;
    @Autowired
    private DeviceInfoService deviceInfoService;
    @Autowired
    private DevParameterDao devParameterDao;
    @Autowired
    private DevParameterRecordDao devParameterRecordDao;
    @Autowired
    private DevParameterService devParamService;
    @Autowired
    private DevMonitorDao devMonitorDao;
    @Autowired
    private DevMaintenRepairDao devMaintenRepairDao;
    @Resource
    private DevRepairRecordDao devRepairRecordDao;
    @Autowired
    private SysDeptDao deptDao;
    @Autowired
    private SysDeptService deptService;
    @Autowired
    private DevMaintenanceTicketDao devMaintenanceTicketDao;
    @Resource
    private DevAmTicketDao devAmTicketDao;
    @Autowired
    private DevMaintenanceTicketItemDao devPmTicketItemDao;
    @Autowired
    private DevAmTicketItemDao devAmTicketItemDao;

    /**
     * doStatDevPmTicketNumDistribution
     *
     * @param param
     * @return
     */
    @Override
    public BarChartOptionModel<Integer> doStatDevPmTicketNumDistribution(Map<String, Object> param) {
        BarChartOptionModel<Integer> barChartOptionModel = new BarChartOptionModel<>();
        BarChartSeriesModel<Integer> completeDevPmTicketNumChartSeriesModel = new BarChartSeriesModel<>("完成工单数");
        BarChartSeriesModel<Integer> unCompleteDevPmTicketNumChartSeriesModel = new BarChartSeriesModel<>("延期工单数");
        BarChartSeriesModel<Integer> completeDevPmTicketItemNumChartSeriesModel = new BarChartSeriesModel<>("完成维护项数");
        BarChartSeriesModel<Integer> unCompleteDevPmTicketItemNumChartSeriesModel = new BarChartSeriesModel<>("延期维护项数");
        /*
            从请求参数中获取statMonthlyNum参数，即需要统计的最近月份数
            如果月份数大于1，那么先统不含本月的前几个月的统计数据 + 本月不包含本周次的周次统计
            整体思路：
                1、首先统计到上月为止的每月的维修工单数，以月为统计单位
                2、统计本月的工单数，以周为统计单位
         */
        // 默认统计近6个月的工单信息
        int statMonthlyNum = com.sugon.modules.utils.MapUtil.getInt(param, "statMonthlyNum", 6);
        if (statMonthlyNum <= 0) {
            statMonthlyNum = 6;
        }
        // 获取PM工单所属车间
        String deptId = MapUtil.getStr(param, "deptCode");
        // 获取工单类别
        String ticketType = MapUtil.getStr(param, "ticketType");
        // 权限sql
        String filterSql = MapUtil.getStr(param, "filterSql");

        Date currentDate = DateUtil.date();
        Date statStartDate, statEndDate;
        // 首先统计近n个月到上个月为止的数据
        if (statMonthlyNum > 1) {
            // 获取统计的开始和结束日期
            statStartDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(currentDate, 1 - statMonthlyNum));
            statEndDate = DateUtil.endOfMonth(DateUtil.offsetMonth(currentDate, -1));
            // 进行设备维护工单完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketMonthlyStatResult = doDevPmTicketDistributionNumStat(deptId, statStartDate, statEndDate, "MONTHLY", ticketType, filterSql);
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketItemMonthlyStatResult = doDevPmTicketItemDistributionNumStat(deptId, statStartDate, statEndDate, "MONTHLY", ticketType, filterSql);

            for (int i = 0; i < statMonthlyNum - 1; i++) {
                String monthly = DateUtil.format(DateUtil.offsetMonth(statStartDate, i), "yyyy-MM");
                barChartOptionModel.addXAxisData(monthly);
                Map<Integer, Integer> tem = devPmTicketMonthlyStatResult.get(monthly);
                int completedNum = 0, delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceTicketStatus.COMPLETE) || entry.getKey().equals(DevMaintenanceTicketStatus.DELAY_COMPLETE)) {
                            completedNum += entry.getValue();
                        } else {
                            delayedNum += entry.getValue();
                        }
                    }
                }
                completeDevPmTicketNumChartSeriesModel.add(completedNum);
                unCompleteDevPmTicketNumChartSeriesModel.add(delayedNum);

                tem = devPmTicketItemMonthlyStatResult.get(monthly);
                completedNum = 0;
                delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceItemExecuteStatus.UN)) {
                            delayedNum += entry.getValue();
                        } else {
                            completedNum += entry.getValue();
                        }
                    }
                }
                completeDevPmTicketItemNumChartSeriesModel.add(completedNum);
                unCompleteDevPmTicketItemNumChartSeriesModel.add(delayedNum);
            }
        }
        // 统计当前月到上周为止的数据
        int weekOfMonth = DateUtil.weekOfMonth(currentDate);
        if (weekOfMonth > 1) {
            // 将本月一号所在的每周周一作为统计开始日期
            statStartDate = DateUtil.beginOfWeek(DateUtil.beginOfMonth(currentDate));
            // 将上一周结束日期作为结束周
            statEndDate = DateUtil.endOfWeek(DateUtil.offsetWeek(currentDate, -1));
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketMonthlyStatResult = doDevPmTicketDistributionNumStat(deptId, statStartDate, statEndDate, "WEEKLY", ticketType, filterSql);
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketItemMonthlyStatResult = doDevPmTicketItemDistributionNumStat(deptId, statStartDate, statEndDate, "WEEKLY", ticketType, filterSql);
            for (int i = 1; i < weekOfMonth; i++) {
                barChartOptionModel.addXAxisData(StrUtil.format("第{}周", i));
                Map<Integer, Integer> tem = devPmTicketMonthlyStatResult.get(i + "");
                int completedNum = 0, delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceTicketStatus.COMPLETE) || entry.getKey().equals(DevMaintenanceTicketStatus.DELAY_COMPLETE)) {
                            completedNum += entry.getValue();
                        } else {
                            delayedNum += entry.getValue();
                        }
                    }
                }
                completeDevPmTicketNumChartSeriesModel.add(completedNum);
                unCompleteDevPmTicketNumChartSeriesModel.add(delayedNum);
                // 设置维护项相关
                tem = devPmTicketItemMonthlyStatResult.get(i + "");
                completedNum = 0;
                delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceItemExecuteStatus.UN)) {
                            delayedNum += entry.getValue();
                        } else {
                            completedNum += entry.getValue();
                        }
                    }
                }
                completeDevPmTicketItemNumChartSeriesModel.add(completedNum);
                unCompleteDevPmTicketItemNumChartSeriesModel.add(delayedNum);
            }
        }
        barChartOptionModel.addBarSeriesData(completeDevPmTicketNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(unCompleteDevPmTicketNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(completeDevPmTicketItemNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(unCompleteDevPmTicketItemNumChartSeriesModel);
        return barChartOptionModel;
    }

    @Override
    public BarChartOptionModel<Integer> doStatDevAmTicketNumDistribution(Map<String, Object> param) {
        BarChartOptionModel<Integer> barChartOptionModel = new BarChartOptionModel<>();
        BarChartSeriesModel<Integer> completeDevAmTicketNumChartSeriesModel = new BarChartSeriesModel<>("完成工单数");
        BarChartSeriesModel<Integer> unCompleteDevAmTicketNumChartSeriesModel = new BarChartSeriesModel<>("延期工单数");
        BarChartSeriesModel<Integer> completeDevAmTicketItemNumChartSeriesModel = new BarChartSeriesModel<>("完成维护项数");
        BarChartSeriesModel<Integer> unCompleteDevAmTicketItemNumChartSeriesModel = new BarChartSeriesModel<>("延期维护项数");
        /*
            从请求参数中获取statMonthlyNum参数，即需要统计的最近月份数
            如果月份数大于1，那么先统不含本月的前几个月的统计数据 + 本月不包含本周次的周次统计
            整体思路：
                1、首先统计到上月为止的每月的维修工单数，以月为统计单位
                2、统计本月的工单数，以周为统计单位
         */
        // 默认统计近6个月的工单信息
        int statMonthlyNum = com.sugon.modules.utils.MapUtil.getInt(param, "statMonthlyNum", 6);
        if (statMonthlyNum <= 0) {
            statMonthlyNum = 6;
        }
        // 获取PM工单所属车间
        String deptId = MapUtil.getStr(param, "deptCode");
        // 获取工单类别
        String ticketType = MapUtil.getStr(param, "ticketType");
        // 权限sql
        String filterSql = MapUtil.getStr(param, "filterSql");

        Date currentDate = DateUtil.date();
        Date statStartDate, statEndDate;
        // 首先统计近n个月到上个月为止的数据
        if (statMonthlyNum > 1) {
            // 获取统计的开始和结束日期
            statStartDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(currentDate, 1 - statMonthlyNum));
            statEndDate = DateUtil.endOfMonth(DateUtil.offsetMonth(currentDate, -1));
            // 进行设备维护工单完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketMonthlyStatResult = doDevAmTicketDistributionNumStat(deptId, statStartDate, statEndDate, "MONTHLY", ticketType, filterSql);
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devPmTicketItemMonthlyStatResult = doDevAmTicketItemDistributionNumStat(deptId, statStartDate, statEndDate, "MONTHLY", ticketType, filterSql);

            for (int i = 0; i < statMonthlyNum - 1; i++) {
                String monthly = DateUtil.format(DateUtil.offsetMonth(statStartDate, i), "yyyy-MM");
                barChartOptionModel.addXAxisData(monthly);
                Map<Integer, Integer> tem = devPmTicketMonthlyStatResult.get(monthly);
                int completedNum = 0, delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        // 完成和延期完成都算完成
                        if (entry.getKey().equals(DevMaintenanceTicketStatus.COMPLETE) || entry.getKey().equals(DevMaintenanceTicketStatus.DELAY_COMPLETE)) {
                            completedNum += entry.getValue();
                        } else {
                            delayedNum += entry.getValue();
                        }
                    }
                }
                completeDevAmTicketNumChartSeriesModel.add(completedNum);
                unCompleteDevAmTicketNumChartSeriesModel.add(delayedNum);

                tem = devPmTicketItemMonthlyStatResult.get(monthly);
                completedNum = 0;
                delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceItemExecuteStatus.UN)) {
                            delayedNum += entry.getValue();
                        } else {
                            completedNum += entry.getValue();
                        }
                    }
                }
                completeDevAmTicketItemNumChartSeriesModel.add(completedNum);
                unCompleteDevAmTicketItemNumChartSeriesModel.add(delayedNum);
            }
        }
        // 统计当前月到上周为止的数据
        int weekOfMonth = DateUtil.weekOfMonth(currentDate);
        if (weekOfMonth > 1) {
            // 将本月一号所在的每周周一作为统计开始日期
            statStartDate = DateUtil.beginOfWeek(DateUtil.beginOfMonth(currentDate));
            // 将上一周结束日期作为结束周
            statEndDate = DateUtil.endOfWeek(DateUtil.offsetWeek(currentDate, -1));
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devAmTicketMonthlyStatResult = doDevAmTicketDistributionNumStat(deptId, statStartDate, statEndDate, "WEEKLY", ticketType, filterSql);
            // 进行设备维护工单项完成数和未完成数统计
            Map<String, Map<Integer, Integer>> devAmTicketItemMonthlyStatResult = doDevAmTicketItemDistributionNumStat(deptId, statStartDate, statEndDate, "WEEKLY", ticketType, filterSql);
            for (int i = 1; i < weekOfMonth; i++) {
                barChartOptionModel.addXAxisData(StrUtil.format("第{}周", i));
                Map<Integer, Integer> tem = devAmTicketMonthlyStatResult.get(i + "");
                int completedNum = 0, delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceTicketStatus.COMPLETE) || entry.getKey().equals(DevMaintenanceTicketStatus.DELAY_COMPLETE)) {
                            completedNum += entry.getValue();
                        } else {
                            delayedNum += entry.getValue();
                        }
                    }
                }
                completeDevAmTicketNumChartSeriesModel.add(completedNum);
                unCompleteDevAmTicketNumChartSeriesModel.add(delayedNum);
                // 设置维护项相关
                tem = devAmTicketItemMonthlyStatResult.get(i + "");
                completedNum = 0;
                delayedNum = 0;
                if (CollectionUtil.isNotEmpty(tem)) {
                    Set<Map.Entry<Integer, Integer>> entries = tem.entrySet();
                    for (Map.Entry<Integer, Integer> entry : entries) {
                        if (entry.getKey().equals(DevMaintenanceItemExecuteStatus.UN)) {
                            delayedNum += entry.getValue();
                        } else {
                            completedNum += entry.getValue();
                        }
                    }
                }
                completeDevAmTicketItemNumChartSeriesModel.add(completedNum);
                unCompleteDevAmTicketItemNumChartSeriesModel.add(delayedNum);
            }
        }
        barChartOptionModel.addBarSeriesData(completeDevAmTicketNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(unCompleteDevAmTicketNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(completeDevAmTicketItemNumChartSeriesModel);
        barChartOptionModel.addBarSeriesData(unCompleteDevAmTicketItemNumChartSeriesModel);
        return barChartOptionModel;
    }

    /**
     * 获取
     * 内部方法，干两件事
     * 1、获取指定起止日期区间内的工单统计
     * 2、整理数据
     * <p>
     * String deptId 车间ID
     *
     * @param statStartDate
     * @param statEndDate
     * @param ticketType    工单类别
     * @return
     */
    private Map<String, Map<Integer, Integer>> doDevAmTicketDistributionNumStat(String deptId, Date statStartDate, Date statEndDate, String dimension, String ticketType, String filterSql) {
        Map<String, Map<Integer, Integer>> statResult = new HashMap<>();
        Map<String, Object> param = new HashMap<>(5);
        param.put("deptId", deptId);
        param.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        param.put("statEndDate", DateUtil.formatDateTime(statEndDate));
        param.put("dimension", dimension);
        param.put("ticketType", ticketType);
        param.put("filterSql", filterSql);
        List<Map<String, Object>> devPmTicketStatResultList = devAmTicketDao.doDevPmTicketDistributionNumStat(param);
        if (CollectionUtil.isNotEmpty(devPmTicketStatResultList)) {
            for (Map<String, Object> devPmTicketStatResult : devPmTicketStatResultList) {
                String dateRangeStr = MapUtil.getStr(devPmTicketStatResult, "DATE_STR");
                if (!statResult.containsKey(dateRangeStr)) {
                    statResult.put(dateRangeStr, new HashMap<>());
                }
                statResult.get(dateRangeStr).put(MapUtil.getInt(devPmTicketStatResult, "STATUS"), MapUtil.getInt(devPmTicketStatResult, "NUM"));
            }
        }
        return statResult;
    }

    /**
     * 统计维护工单完成项 完成状况统计
     * <p>
     * 获取
     * 内部方法，干两件事
     * 1、获取指定起止日期区间内的工单统计
     * 2、整理数据
     * <p>
     * String deptId 车间ID
     *
     * @param statStartDate
     * @param statEndDate
     * @param ticketType    工单类别
     * @return
     */
    private Map<String, Map<Integer, Integer>> doDevAmTicketItemDistributionNumStat(String deptId, Date statStartDate, Date statEndDate, String dimension, String ticketType, String filterSql) {
        Map<String, Map<Integer, Integer>> statResult = new HashMap<>();
        Map<String, Object> param = new HashMap<>(5);
        param.put("deptId", deptId);
        param.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        param.put("statEndDate", DateUtil.formatDateTime(statEndDate));
        param.put("dimension", dimension);
        param.put("ticketType", ticketType);
        param.put("filterSql", filterSql);
        List<Map<String, Object>> devPmTicketStatResultList = devAmTicketItemDao.doDevAmTicketItemDistributionNumStat(param);
        if (CollectionUtil.isNotEmpty(devPmTicketStatResultList)) {
            for (Map<String, Object> devPmTicketStatResult : devPmTicketStatResultList) {
                String dateRangeStr = MapUtil.getStr(devPmTicketStatResult, "DATE_STR");
                if (!statResult.containsKey(dateRangeStr)) {
                    statResult.put(dateRangeStr, new HashMap<>());
                }
                statResult.get(dateRangeStr).put(MapUtil.getInt(devPmTicketStatResult, "STATUS"), MapUtil.getInt(devPmTicketStatResult, "NUM"));
            }
        }
        return statResult;
    }

    /**
     * 获取
     * 内部方法，干两件事
     * 1、获取指定起止日期区间内的工单统计
     * 2、整理数据
     * <p>
     * String deptId 车间ID
     *
     * @param statStartDate
     * @param statEndDate
     * @param ticketType    工单类别
     * @return
     */
    private Map<String, Map<Integer, Integer>> doDevPmTicketDistributionNumStat(String deptId, Date statStartDate, Date statEndDate, String dimension, String ticketType, String filterSql) {
        Map<String, Map<Integer, Integer>> statResult = new HashMap<>();
        Map<String, Object> param = new HashMap<>(5);
        param.put("deptId", deptId);
        param.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        param.put("statEndDate", DateUtil.formatDateTime(statEndDate));
        param.put("dimension", dimension);
        param.put("ticketType", ticketType);
        param.put("filterSql", filterSql);
        List<Map<String, Object>> devPmTicketStatResultList = devMaintenanceTicketDao.doDevPmTicketDistributionNumStat(param);
        if (CollectionUtil.isNotEmpty(devPmTicketStatResultList)) {
            for (Map<String, Object> devPmTicketStatResult : devPmTicketStatResultList) {
                String dateRangeStr = MapUtil.getStr(devPmTicketStatResult, "DATE_STR");
                if (!statResult.containsKey(dateRangeStr)) {
                    statResult.put(dateRangeStr, new HashMap<>());
                }
                statResult.get(dateRangeStr).put(MapUtil.getInt(devPmTicketStatResult, "STATUS"), MapUtil.getInt(devPmTicketStatResult, "NUM"));
            }
        }
        return statResult;
    }

    /**
     * 统计维护工单完成项 完成状况统计
     * <p>
     * 获取
     * 内部方法，干两件事
     * 1、获取指定起止日期区间内的工单统计
     * 2、整理数据
     * <p>
     * String deptId 车间ID
     *
     * @param statStartDate
     * @param statEndDate
     * @param ticketType    工单类别
     * @return
     */
    private Map<String, Map<Integer, Integer>> doDevPmTicketItemDistributionNumStat(String deptId, Date statStartDate, Date statEndDate, String dimension, String ticketType, String filterSql) {
        Map<String, Map<Integer, Integer>> statResult = new HashMap<>();
        Map<String, Object> param = new HashMap<>(5);
        param.put("deptId", deptId);
        param.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        param.put("statEndDate", DateUtil.formatDateTime(statEndDate));
        param.put("dimension", dimension);
        param.put("ticketType", ticketType);
        param.put("filterSql", filterSql);
        List<Map<String, Object>> devPmTicketStatResultList = devPmTicketItemDao.doDevPmTicketItemDistributionNumStat(param);
        if (CollectionUtil.isNotEmpty(devPmTicketStatResultList)) {
            for (Map<String, Object> devPmTicketStatResult : devPmTicketStatResultList) {
                String dateRangeStr = MapUtil.getStr(devPmTicketStatResult, "DATE_STR");
                if (!statResult.containsKey(dateRangeStr)) {
                    statResult.put(dateRangeStr, new HashMap<>());
                }
                statResult.get(dateRangeStr).put(MapUtil.getInt(devPmTicketStatResult, "STATUS"), MapUtil.getInt(devPmTicketStatResult, "NUM"));
            }
        }
        return statResult;
    }

    /**
     * doStatDevRepairTicketNumDistribution
     *
     * @param param
     * @return
     */
    @Override
    public BarChartOptionModel<Integer> doStatDevRepairTicketNumDistribution(Map<String, Object> param) {

        BarChartOptionModel<Integer> barChartOptionModel = new BarChartOptionModel<>();
        BarChartSeriesModel<Integer> barChartSeriesModel = new BarChartSeriesModel<>();
        /*
            从请求参数中获取statMonthlyNum参数，即需要统计的最近月份数
            如果月份数大于1，那么先统不含本月的前几个月的统计数据 + 本月不包含本周次的周次统计
            整体思路：
                1、首先统计到上月为止的每月的维修工单数，以月为统计单位
                2、统计本月的工单数，以周为统计单位
         */
        // 默认统计近6个月的工单信息
        int statMonthlyNum = com.sugon.modules.utils.MapUtil.getInt(param, "statMonthlyNum", 6);
        if (statMonthlyNum <= 0) {
            statMonthlyNum = 6;
        }
        Date currentDate = DateUtil.date();
        Date statStartDate, statEndDate;
        // 首先统计近n个月到上个月为止的数据
        if (statMonthlyNum > 1) {
            // 获取统计的开始和结束日期
            statStartDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(currentDate, 1 - statMonthlyNum));
            statEndDate = DateUtil.endOfMonth(DateUtil.offsetMonth(currentDate, -1));
            Map<String, Integer> devRepairTicketMonthlyStatResult = doDevRepairTicketDistributionNumStat(statStartDate, statEndDate, "MONTHLY");
            for (int i = 0; i < statMonthlyNum - 1; i++) {
                String monthly = DateUtil.format(DateUtil.offsetMonth(statStartDate, i), "yyyy-MM");
                barChartOptionModel.addXAxisData(monthly);
                barChartSeriesModel.add(com.sugon.modules.utils.MapUtil.getInt(devRepairTicketMonthlyStatResult, monthly, 0));
            }
        }
        // 统计当前月到上周为止的数据
        int weekOfMonth = DateUtil.weekOfMonth(currentDate);
        if (weekOfMonth > 1) {
            // 将本月一号日期作为统计开始日期
            statStartDate = DateUtil.beginOfMonth(currentDate);
            // 将上一周结束日期作为结束周
            statEndDate = DateUtil.endOfWeek(DateUtil.offsetWeek(currentDate, -1));
            Map<String, Integer> devRepairTicketMonthlyStatResult = doDevRepairTicketDistributionNumStat(statStartDate, statEndDate, "WEEKLY");
            for (int i = 1; i < weekOfMonth; i++) {
                barChartOptionModel.addXAxisData(StrUtil.format("第{}周", i));
                barChartSeriesModel.add(com.sugon.modules.utils.MapUtil.getInt(devRepairTicketMonthlyStatResult, i + "", 0));
            }
        }
        barChartOptionModel.addBarSeriesData(barChartSeriesModel);
        return barChartOptionModel;
    }


    /**
     * 内部方法，干两件事
     * 1、获取指定起止日期区间内的工单统计
     * 2、整理数据
     *
     * @param statStartDate
     * @param statEndDate
     * @return
     */
    private Map<String, Integer> doDevRepairTicketDistributionNumStat(Date statStartDate, Date statEndDate, String dimension) {
        Map<String, Integer> statResult = new HashMap<>();
        Map<String, Object> param = new HashMap<>(3);
        param.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        param.put("statEndDate", DateUtil.formatDateTime(statEndDate));
        param.put("dimension", dimension);
        List<Map<String, Object>> devRepairTicketStatResultList = devRepairRecordDao.doDevRepairTicketDistributionNumStat(param);
        if (CollectionUtil.isNotEmpty(devRepairTicketStatResultList)) {
            for (Map<String, Object> devRepairTicketStatResult : devRepairTicketStatResultList) {
                statResult.put(MapUtil.getStr(devRepairTicketStatResult, "DATE_STR"), MapUtil.getInt(devRepairTicketStatResult, "NUM"));
            }
        }
        return statResult;
    }

    /**
     * 获取故障时长统计
     * 从（故障上报-效果确认）和（维修开始-维修结束）两个维度进行处理
     *
     * @param param
     * @return
     */
    @Override
    public BarChartOptionModel getFaultDurationStat(Map<String, Object> param) {
        BarChartOptionModel faultDurationStatChartModel = new BarChartOptionModel();
        BarChartSeriesModel<Integer> faultTimeBar = new BarChartSeriesModel<>();
        BarChartSeriesModel<Integer> weixiuTimeBar = new BarChartSeriesModel<>();
        BarChartSeriesModel<Integer> yunxingTimeBar = new BarChartSeriesModel<>();
        // 获取设备故障时长
        List<Map<String, Object>> faultDurationStatList = devMaintenWorkDao.getFaultDurationStat(param);
        // 判断获取设备故障时长数据是否为空
        if (CollectionUtil.isNotEmpty(faultDurationStatList)) {
            int natureTime = getCurMonthNatureTimeMiniutes();
            for (Map<String, Object> faultDurationStat : faultDurationStatList) {
                String dcode = MapUtil.getStr(faultDurationStat, "DCODE");
                if (StrUtil.isEmpty(dcode)) {
                    continue;
                }
                faultDurationStatChartModel.addXAxisData(dcode);
                // 获取故障时间
                int faultTime = com.sugon.utils.MapUtil.getInt(faultDurationStat, "FAULTTIME", 0);
                faultTimeBar.add(faultTime);
                // 获取维修时间
                weixiuTimeBar.add(com.sugon.utils.MapUtil.getInt(faultDurationStat, "WEIXIUTIME", 0));
                // 运行时间
                yunxingTimeBar.add(natureTime - faultTime);
            }
        }
        faultDurationStatChartModel.addBarSeriesData(weixiuTimeBar);
        faultDurationStatChartModel.addBarSeriesData(faultTimeBar);
        faultDurationStatChartModel.addBarSeriesData(yunxingTimeBar);
        return faultDurationStatChartModel;
    }

    /**
     * 获取本月自然时间分钟数
     * 即从月初到现在已经过来多少分钟
     *
     * @return
     */
    private static Integer getCurMonthNatureTimeMiniutes() {
        // 当前时间
        Date now = DateUtil.date();
        // 本月第一天
        Date first = DateUtil.beginOfMonth(DateUtil.date());
        return (int) DateUtil.between(first, now, DateUnit.MINUTE);
    }

    /**
     * faultHandleDurationTopWorkStat
     *
     * @param param
     * @return
     */
    @Override
    public List<FaultHandleDurationTopWorkVO> faultHandleDurationTopWorkStat(Map<String, Object> param) {
        com.sugon.utils.MapUtil.removeEmptyValue(param);
        if (!param.containsKey("orderField")) {
            param.put("orderField", "JIEDAN");
        }
        List<FaultHandleDurationTopWorkVO> list = devMaintenWorkDao.faultHandleDurationTopWorkStat(param);
        return list;
    }

    /**
     * deptMaintainNumStat
     *
     * @param deptCode
     * @return
     */
    @Override
    public DeptWorkAndMaintainStat deptMaintainNumStat(String deptCode) {
        DeptWorkAndMaintainStat result = new DeptWorkAndMaintainStat();
        SysDeptEntity dept = deptService.getByDCode(deptCode);
        if (dept != null) {
            // 1、从维修计划中统计今日维护计划执行情况
            setMaintainPlanStat(result, dept.getDeptId());
            //2、从报修工单中统计执行信息
            setWorkOrderStat(result, dept.getDeptId());
        }
        return result;
    }

    /**
     * 设置今天维护计划统计
     *
     * @param result
     * @param deptId
     */
    private void setMaintainPlanStat(DeptWorkAndMaintainStat result, String deptId) {
        // 获取本周未完成的工单列表
        List<Map<String, Object>> todayGCStatusStat = devMaintenanceTicketDao.statIngDeptDeviceTicket(deptId);
        int wd = 0, un = 0, ing = 0, ed = 0;
        if (CollectionUtil.isNotEmpty(todayGCStatusStat)) {
            for (Map<String, Object> gcStat : todayGCStatusStat) {
                int status = com.sugon.modules.utils.MapUtil.getInt(gcStat, "STATUS", 0);
                int count = com.sugon.modules.utils.MapUtil.getInt(gcStat, "TIMES", 0);
                if (status == DevMaintenanceTicketStatus.DISPATCHING) {
                    wd += count;
                } else if (status <= DevMaintenanceTicketStatus.WAIT_EXECUTE) {
                    un += count;
                } else if (status <= DevMaintenanceTicketStatus.DELAY_MAINTAINING) {
                    ing += count;
                } else if (status == DevMaintenanceTicketStatus.COMPLETE) {
                    ed += count;
                }
            }
        }
        result.setMaintainPlanStat(new DeptWorkAndMaintainStatItem(wd, un, ing, ed));
    }

    /**
     * 设置报修工单信息
     *
     * @param result
     * @param deptCode
     */
    private void setWorkOrderStat(DeptWorkAndMaintainStat result, String deptCode) {
        // 获取当前组织下的工单执行情况
        List<Map<String, Object>> todayGCStatusStat = devMaintenWorkDao.setWorkOrderStat(deptCode);
        int wd = 0, un = 0, ing = 0, ed = 0;
        // 判断当前组织工单数据是否为空
        if (CollectionUtil.isNotEmpty(todayGCStatusStat)) {
            for (Map<String, Object> gcStat : todayGCStatusStat) {
                int status = com.sugon.modules.utils.MapUtil.getInt(gcStat, "DEV_STATUS", 0);
                int count = com.sugon.modules.utils.MapUtil.getInt(gcStat, "COUNT", 0);
                /*
                    待维修数：已派工但维修人员尚未开始的维修数
                    执行中：开始维修 ~ 维修结束
                    已结束：维修结束后的工单
                 */
                if (status == DevRepairTicketStage.CALL_REPAIR) {
                    wd += count;
                } else if (status >= DevRepairTicketStage.START_REPAIR && status <= DevRepairTicketStage.END_REPAIR) {
                    ing += count;
                } else if (status > DevRepairTicketStage.END_REPAIR) {
                    ed += count;
                }
            }
        }
        result.setWorkOrderStat(new DeptWorkAndMaintainStatItem(wd, un, ing, ed));
    }

    /**
     * statDevFaultTypeTimeAndRate
     *
     * @param month 查询参数，包含月份
     * @return
     */
    @Override
    public DevFaultTypeTimeStat statDevFaultTypeTimeAndRate(String month) {

        DevFaultTypeTimeStat devFaultTypeTimeStat = new DevFaultTypeTimeStat();

        int totalTime = 0;
        // 获取设备故障大类别次数统计列表
        List<Map<String, Object>> devFaultTypeTimeList = devMaintenRepairDao.statDevFaultTypeTime(month);
        if (CollectionUtil.isNotEmpty(devFaultTypeTimeList)) {
            for (Map<String, Object> devFaultTypeTime : devFaultTypeTimeList) {
                devFaultTypeTimeStat.add(MapUtil.getStr(devFaultTypeTime, "TYPE_NAME"), MapUtil.getInt(devFaultTypeTime, "TIMES"));
                totalTime += MapUtil.getInt(devFaultTypeTime, "TIMES");
            }
        }
        // 计算百分比
        int computeTime = 0;
        List<Integer> faultTimes = devFaultTypeTimeStat.getFaultTimes();
        for (Integer faultTime : faultTimes) {
            computeTime += faultTime;
            devFaultTypeTimeStat.getAccumulativeRate().add(totalTime == 0 ? 0 : computeTime * 100 / totalTime);
        }
        return devFaultTypeTimeStat;
    }

    /**
     * doDevFaultTopStat
     *
     * @param param
     * @return
     */
    @Override
    public FaultTopStatVO doDevFaultTopStat(Map<String, Object> param) {
        FaultTopStatVO faultTopStatVO = new FaultTopStatVO();
        // 移除map中value为空或空字符串的键值对
        com.sugon.utils.MapUtil.removeEmptyValue(param);
        // 根根查询关键字执行故障次数和故障时长统计信息
        String keyword = com.sugon.utils.MapUtil.getStr(param, "keyword", "times");

        List<Map<String, Object>> topDevStatList = "times".equals(keyword) ? devRepairRecordDao.statFaultTimeTopDevList(param) : devRepairRecordDao.statFaultDurationTopDevList(param);
        // 颠倒顺序，便于降序排序
        Collections.reverse(topDevStatList);
        if (CollectionUtil.isNotEmpty(topDevStatList)) {
            for (Map<String, Object> topRepairedDev : topDevStatList) {
                faultTopStatVO.add(MapUtil.getStr(topRepairedDev, "DEV_NAME"), MapUtil.getInt(topRepairedDev, "TIMES"));
            }
        }
        return faultTopStatVO;
    }

    /**
     * loadDeviceParamLineData
     *
     * @param params
     * @return
     */
    @Override
    public DevParamLineChartDataVO loadDeviceParamLineData(Map<String, Object> params) {

        DevParamLineChartDataVO lineChartData = new DevParamLineChartDataVO();
        // 常规校验
        String devCode = MapUtil.getStr(params, "devCode");
        String paramName = MapUtil.getStr(params, "paramName");
        if (StrUtil.isEmpty(devCode) || StrUtil.isEmpty(paramName)) {
            return lineChartData;
        }
        params.put("devCode", "'" + devCode + "'");
        if (params.containsKey("beginTime")) {
            params.put("beginTime", "'" + params.get("beginTime") + "'");
        }
        if (params.containsKey("endTime")) {
            // 对于终止日期，需要获取下一天日期
            String endTime = MapUtil.getStr(params, "endTime");
            String nextDay = DateUtil.formatDate(DateUtil.offset(DateUtil.parseDate(endTime), DateField.DAY_OF_YEAR, 1));
            params.put("endTime", "'" + nextDay + "'");
        }

        // 1、设置右侧颜色区间
        DevParameterEntity devParam = devParamService.queryObject(devCode, paramName);
        Assert.notNull(devParam, "该设备[{0}]下不含有[{1}]参数", devCode, paramName);
        if (devParam.getThresholdMin() != null && devParam.getThresholdMax() != null) {
            lineChartData.addVisualMapPiecesItem(new LineOptionVisualMapPiecesItemVO(0.0, devParam.getThresholdMin(), "#ffde33"));
            lineChartData.addVisualMapPiecesItem(new LineOptionVisualMapPiecesItemVO(devParam.getThresholdMin(), devParam.getThresholdMax(), "#096"));
            lineChartData.addVisualMapPiecesItem(new LineOptionVisualMapPiecesItemVO(devParam.getThresholdMax(), null, "#cc0033"));
            lineChartData.addSeriesMarkLineItem(devParam.getThresholdMin());
            lineChartData.addSeriesMarkLineItem(devParam.getThresholdMax());
        }
        // 2、设置折线图横纵坐标值
        List<Map<String, Object>> deviceParamLineDataList = devParameterRecordDao.loadDeviceParamLineData(params);
        if (CollectionUtil.isNotEmpty(deviceParamLineDataList)) {
            for (Map<String, Object> deviceParamLineData : deviceParamLineDataList) {
                lineChartData.addOptionDataItem(deviceParamLineData.values());
            }
        }
        return lineChartData;
    }

    /**
     * statDevStatusNum
     *
     * @param params
     * @return
     */
    @Override
    public PieChartOptionDataVO statDevStatusNum(Map<String, Object> params) {
        PieChartOptionDataVO pieChartOption = new PieChartOptionDataVO();

        // 获取设备状态统计结果并整理成键值对
        List<Map<String, Object>> devStatusStatResult = devStatusRecordDao.statDevStatusNum(params);
        Map<Integer, Integer> statMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(devStatusStatResult)) {
            for (Map<String, Object> devStatusStat : devStatusStatResult) {
                statMap.put(MapUtil.getInt(devStatusStat, "DEVSTATUS"), MapUtil.getInt(devStatusStat, "DEVNUM"));
            }
        }
        // 封装结果
        boolean isNotEmpty = CollectionUtil.isNotEmpty(statMap);
        DevStatus[] devStatuses = DevStatus.values();
        for (DevStatus devStatus : devStatuses) {
            pieChartOption.addLegendData(devStatus.getDesc());
            if (isNotEmpty) {
                pieChartOption.addSeriesData(new PieChartSeriesDataItemVO(devStatus.getDesc(), statMap.get(devStatus.getValue())));
            }
        }
        return pieChartOption;
    }

    /**
     * statDevPmCompleteRate
     *
     * @param params
     * @return
     */
    @Override
    public PieChartOptionDataVO statDevPmCompleteRate(Map<String, Object> params) {
        PieChartOptionDataVO pieChartOption = new PieChartOptionDataVO();

        /*
             默认统计近6个月(包含本月)的工单信息

         */
        int statMonthlyNum = com.sugon.modules.utils.MapUtil.getInt(params, "statMonthlyNum", 6);
        if (statMonthlyNum <= 0) {
            statMonthlyNum = 6;
        }
        Date currentDate = DateUtil.date();
        Date statStartDate = DateUtil.beginOfMonth(DateUtil.offsetMonth(currentDate, 1 - statMonthlyNum)), statEndDate;
        int weekOfMonth = DateUtil.weekOfMonth(currentDate);
        if (weekOfMonth > 1) {
            // 将上一周结束日期作为结束周
            statEndDate = DateUtil.endOfWeek(DateUtil.offsetWeek(currentDate, -1));
        } else {
            // 将上一周结束日期作为结束周
            statEndDate = DateUtil.endOfMonth(DateUtil.offsetMonth(currentDate, -1));
        }

        // 声明完成和延期工单变量
        int completePmNum = 0, unCompletePmNum = 0;
        // 放置本年度和本周次
        params.put("statStartDate", DateUtil.formatDateTime(statStartDate));
        params.put("statEndDate", DateUtil.formatDateTime(statEndDate));
            /*
                1、获取本年度截止到上周为止的处于不同工单状态的工单数
                2、归类：完成工单和延期工单(完成状态以外的工单)
             */
        List<Map<String, Object>> devPmCompleteRateStatResult = devMaintenanceTicketDao.statDevPmCompleteRateStatusNum(params);
        if (CollectionUtil.isNotEmpty(devPmCompleteRateStatResult)) {
            for (Map<String, Object> devPmCompleteRateStat : devPmCompleteRateStatResult) {
                if (DevMaintenanceTicketStatus.COMPLETE.equals(MapUtil.getInt(devPmCompleteRateStat, "STATUS"))) {
                    completePmNum += MapUtil.getInt(devPmCompleteRateStat, "PM_NUM");
                } else {
                    unCompletePmNum += MapUtil.getInt(devPmCompleteRateStat, "PM_NUM");
                }
            }
        }
        if (completePmNum != 0 && unCompletePmNum != 0) {
            // 设置PM完成率
            pieChartOption.addLegendData("完成率");
            pieChartOption.addSeriesData(new PieChartSeriesDataItemVO("完成率", completePmNum));
            // 设置PM延期率
            pieChartOption.addLegendData("延期率");
            pieChartOption.addSeriesData(new PieChartSeriesDataItemVO("延期率", unCompletePmNum));
        }
        return pieChartOption;
    }

    /**
     * statDeviceAlarmTimeTop
     *
     * @param params
     * @return
     */
    @Override
    public List<DevAlarmTimeTopStatVO> statDeviceAlarmTimeTop(Map<String, Object> params) {

        List<DevAlarmTimeTopStatVO> topStats = new ArrayList<>();

        Map<String, DevAlarmTimeTopStatVO> statMap = new HashMap<>();

        // 1、根据车间、产线、时长 获取所有报警信息，报警信息按照采集时间排序
        List<DevAlarmTimeTopStatItemDTO> topStatItems = devAlarmRecordDao.devAlarmTimeStat(params);
        if (CollectionUtil.isEmpty(topStatItems)) {
            return topStats;
        }

        String devCode, alarmCode;
        DevAlarmTimeTopStatVO statMapValue;
        for (DevAlarmTimeTopStatItemDTO topStatItem : topStatItems) {
            // 检测是否已存在该设备
            devCode = topStatItem.getDevCode();
            // 查看是否已存在该设备记录
            statMapValue = statMap.get(devCode);
            if (statMapValue == null) {
                statMapValue = new DevAlarmTimeTopStatVO(topStatItem);
                statMap.put(devCode, statMapValue);
            }
            // 检测设备下是否存在该报警,如果不存在则创建
            List<DevAlarmTimeTopStatItemVO> devAlarmItems = statMapValue.getAlarmItems();
            DevAlarmTimeTopStatItemVO devAlarmStat = getAlarmTimeStatRecord(devAlarmItems, topStatItem.getDevId(), topStatItem.getCode());
            if (devAlarmStat == null) {
                devAlarmStat = new DevAlarmTimeTopStatItemVO(topStatItem.getDevId(), topStatItem.getCode(), topStatItem.getMsg(), topStatItem.getAlarmDuration());
                devAlarmItems.add(devAlarmStat);
            } else {
                // 累加当前报警的报警时长
                devAlarmStat.setAlarmDuration(devAlarmStat.getAlarmDuration() + +topStatItem.getAlarmDuration());
                devAlarmStat.setTimes(devAlarmStat.getTimes() + 1);
            }
            // 累加设备报警时长
            statMapValue.setAlarmDuration(statMapValue.getAlarmDuration() + topStatItem.getAlarmDuration());
        }
        // Collection -> List
        Collection<DevAlarmTimeTopStatVO> devAlarmTimeTopStatsCol = statMap.values();
        topStats = new ArrayList<>(devAlarmTimeTopStatsCol);
        // 按照报警时长排序
        topStats.sort((g1, g2) -> (int) (g2.getAlarmDuration() - g1.getAlarmDuration()));
        // TOP截取
        topStats = CollectionUtil.sub(topStats, 0, com.sugon.utils.MapUtil.getInt(params, "topNum", 10));
        // 遍历每一个设备下的报警列表，按照时长倒序显示
        for (DevAlarmTimeTopStatVO topStat : topStats) {
            topStat.getAlarmItems().sort((g1, g2) -> (int) (g2.getAlarmDuration() - g1.getAlarmDuration()));
        }
        return topStats;
    }

    /**
     * loadDevParamList
     *
     * @param devCode 设备编码
     * @return
     */
    @Override
    public List<Map<String, Object>> loadDevParamList(String devCode) {
        // 获取设备信息
        DeviceInfoEntity device = deviceInfoService.getInfoByDevCode(devCode);
        if (device != null) {
            String devType = device.getDevTypeS();
            String devSupply = device.getDevSupply();
            // 判断设备类型，和设备厂家 是否为空，
            if (StrUtil.isNotEmpty(devType) && StrUtil.isNotEmpty(devSupply)) {
                Map<String, Object> param = new HashMap<>();
                param.put("devType", devType);
                param.put("devSupply", devSupply);
                return devParameterDao.loadDevParam(param);
            }
        }
        return new ArrayList<>();
    }

    /**
     * 从设备的报警记录中找出对应的报警信息
     *
     * @param devAlarmItems
     * @param devId         设备ID
     * @param alarmCode     报警代码
     * @return
     */
    private DevAlarmTimeTopStatItemVO getAlarmTimeStatRecord(List<DevAlarmTimeTopStatItemVO> devAlarmItems, String devId, String alarmCode) {
        //判断设备报警信息是否为空
        if (CollectionUtil.isNotEmpty(devAlarmItems)) {
            for (DevAlarmTimeTopStatItemVO topStatItem : devAlarmItems) {
                //判断报警码是否相同
                if (devId.equals(topStatItem.getDevId()) && alarmCode.equals(topStatItem.getAlarmCode())) {
                    return topStatItem;
                }
            }
        }
        return null;
    }

    /**
     * statDeviceAlarmRepairCompare
     *
     * @param params
     * @return
     */
    @Override
    public BarChartOptionModel statDeviceAlarmRepairCompare(Map<String, Object> params) {

        BarChartOptionModel<Integer> optionModel = new BarChartOptionModel();
        // 初始化legendData
        List<String> legendData = CollectionUtil.newArrayList("报警频次", "维修频次");
        Collection<String> xAxisData = new ArrayList<>();

        Map<String, Integer> leftTopStat;
        Map<String, Integer> rightTopStat = new LinkedHashMap<>();
        String orderField = MapUtil.getStr(params, "keyword");
        if ("repair".equals(orderField)) {
            legendData = CollectionUtil.reverse(legendData);
            leftTopStat = getRepairTopStat(params);
            if (CollectionUtil.isNotEmpty(leftTopStat)) {
                // 获取x坐标
                xAxisData = leftTopStat.keySet();
                // 将设备编码放置到查询参数中,并查询故障统计
                params.put("devCodes", xAxisData);
                // 获取设备报警次数统计
                rightTopStat = commonHandle(devAlarmRecordDao.statDevAlarmTimes(params));
            }
        } else {
            // 显示报警前多少名
            leftTopStat = getAlarmTopStat(params);
            if (CollectionUtil.isNotEmpty(leftTopStat)) {
                // 获取x坐标
                xAxisData = leftTopStat.keySet();
                // 将设备编码放置到查询参数中,并查询故障统计
                params.put("devCodes", xAxisData);
                rightTopStat = commonHandle(devAlarmRecordDao.statDevRepairTimes(params));
            }
        }
        // 设置legend
        optionModel.setLegendData(legendData);
        // 设置横坐标
        optionModel.setXAxisData(xAxisData);
        // 设置seriesData
        ArrayList<Integer> first = new ArrayList<>();
        ArrayList<Integer> second = new ArrayList<>();
        for (String devCode : xAxisData) {
            first.add(leftTopStat.get(devCode) == null ? 0 : leftTopStat.get(devCode));
            second.add(rightTopStat.get(devCode) == null ? 0 : rightTopStat.get(devCode));
        }
        optionModel.addBarSeriesData(new BarChartSeriesModel<>(legendData.get(0), first));
        optionModel.addBarSeriesData(new BarChartSeriesModel<>(legendData.get(1), second));
        return optionModel;
    }

    /**
     * 获取报警TOP统计
     *
     * @param param
     * @return
     */
    private Map<String, Integer> getAlarmTopStat(Map<String, Object> param) {
        //判断部门ID是否为空
        if (param.get("curDeptId") != null) {
            param.put("curDeptId", param.get("curDeptId") + "%");
        }
        Map<String, Integer> alarmTopStat = new LinkedHashMap<>();
        List<Map<String, Object>> devAlarmStatList = devAlarmRecordDao.statDevAlarm(param);
        //判断报警信息是否为空
        if (CollectionUtil.isNotEmpty(devAlarmStatList)) {
            for (Map<String, Object> devAlarmStat : devAlarmStatList) {
                alarmTopStat.put(MapUtil.getStr(devAlarmStat, "DEVCODE"), MapUtil.getInt(devAlarmStat, "TIMES"));
            }
        }
        return alarmTopStat;
    }

    /**
     * 获取报警TOP统计
     *
     * @param param
     * @return
     */
    private Map<String, Integer> getRepairTopStat(Map<String, Object> param) {
        // 判断部门ID是否为空
        if (param.get("curDeptId") != null) {
            param.put("curDeptId", param.get("curDeptId") + "%");
        }
        Map<String, Integer> alarmTopStat = new LinkedHashMap<>();
        List<Map<String, Object>> devRepairStatList = devAlarmRecordDao.statDevRepair(param);
        if (CollectionUtil.isNotEmpty(devRepairStatList)) {
            for (Map<String, Object> devRepairStat : devRepairStatList) {
                alarmTopStat.put(MapUtil.getStr(devRepairStat, "DEVCODE"), MapUtil.getInt(devRepairStat, "TIMES"));
            }
        }
        return alarmTopStat;
    }

    /**
     * 将mybatis中返回的查询结果List<Map<String, Object>> -> Map<String, Integer>
     * key: 设备编码 value次数
     *
     * @param handleTargets 处理类型
     * @return
     */
    private Map<String, Integer> commonHandle(List<Map<String, Object>> handleTargets) {
        Map<String, Integer> hanldeResult = new LinkedHashMap<>();
        if (CollectionUtil.isNotEmpty(handleTargets)) {
            for (Map<String, Object> handleTarget : handleTargets) {
                hanldeResult.put(MapUtil.getStr(handleTarget, "DEVCODE"), MapUtil.getInt(handleTarget, "TIMES"));
            }
        }
        return hanldeResult;
    }

    /**
     * @return java.util.Map<java.lang.String, java.lang.Object>
     * @Description 可以把相关的返回写成实体，避免大小写转换
     * @Author fazi
     * @Date 2020/6/7 19:09
     * @Param [devCode]
     **/
    @Override
    public Map<String, Object> deviceMonitor(@RequestParam String devCode) {
        Map<String, Object> map = new HashMap<>();
        // 设备报警数
        map.put("alarmCount", devMonitorDao.queryAlarmCount(devCode));
        // 设备故障数
        map.put("faultCount", devMonitorDao.queryFaultCount(devCode));
        // 设备故障和报警数统计对比
        List<String> x = new ArrayList<>();
        // 报警
        List<Object> y1 = new ArrayList<>();
        // 设置近七天设备报警次数统计
        for (Map map2 : devMonitorDao.queryAlarmInfo(devCode)) {
            x.add((String) map2.get("name"));
            y1.add(map2.get("value"));
        }
        // 查询近七天设备故障次数统计
        List<Object> y2 = new ArrayList<>();
        for (Map map2 : devMonitorDao.queryFaultInfo(devCode)) {
            y2.add(map2.get("value"));
        }
        map.put("x", x);
        map.put("y1", y1);
        map.put("y2", y2);

        // 设备详情
        map.put("baseInfo", devMonitorDao.queryDeviceInfo(devCode));
        // 设备更换备件信息
        List<Map<String, Object>> c = devMonitorDao.querySpareInfo(devCode);
        map.put("spareInfo", c == null ? new ArrayList<>() : c);
        // 设备状态时间分布统计
        List<Map<String, Object>> devStatusDurationStatList = devMonitorDao.queryStatusDateInfo(devCode);

        PieChartOptionDataVO devStatusDurationOption = new PieChartOptionDataVO();
        for (Map<String, Object> devStatusDurationStat : devStatusDurationStatList) {
            DevStatus devStatus = DevStatus.getInstance(MapUtil.getInt(devStatusDurationStat, "DEVSTATUS"));
            devStatusDurationOption.addLegendData(devStatus.getDesc());
            devStatusDurationOption.addSeriesData(new PieChartSeriesDataItemVO(devStatus.getDesc(), MapUtil.getInt(devStatusDurationStat, "DURATION")));
        }
        map.put("devStatusDurationStat", devStatusDurationOption);
        // 设备故障时长统计分析
        // 统计设备分别发生了哪些故障和故障时长占比
        List<Map<String, Object>> e = devMonitorDao.queryFaultDateInfo(devCode);
        map.put("faultDate", e == null ? new ArrayList<>() : e);
        return map;
    }

    /**
     * doAreaDeviceFaultTimeStat
     *
     * @param dcode 设备组织CODE
     * @param month 月份
     * @return
     */
    @Override
    public BarChartOptionModel doAreaDeviceFaultTimeStat(String dcode, String month) {

        BarChartOptionModel<Integer> areaDeviceFaultTimeStat = new BarChartOptionModel();
        // 如果未传递DCODE，那么默认查询铸造二车间的
        if (StrUtil.isEmpty(dcode)) {
            dcode = "ZZ2";
        }
        // 1、根据部门级别获取列名
        SysDeptEntity pdept = deptService.getByDCode(dcode);
        Assert.notNull(pdept, "部门[{0}]信息不存在,请确认", dcode);
        String columnName = pdept.getDeptLevel().intValue() == 2 ? "DEV_PRODUCT_CODE" : "DEV_PROCE_NO";
        // 2、获取所有子部门CODE
        List<String> subDeptDCodes = deptDao.getSubDeptDCode(pdept.getDeptId());
        if (CollectionUtil.isEmpty(subDeptDCodes)) {
            return areaDeviceFaultTimeStat;
        }
        areaDeviceFaultTimeStat.setXAxisData(subDeptDCodes);
        // 初始化柱状体SeriesModel
        BarChartSeriesModel<Integer> areaFaultTimeStat = new BarChartSeriesModel<>();
        // 3、查询区域设备故障次数统计
        Map<String, Integer> getDBAreaFaultTimeStat = getDBAreaFaultTimeStat(pdept.getDeptId(), month, columnName);
        for (String areaCode : subDeptDCodes) {
            areaFaultTimeStat.add(com.sugon.utils.MapUtil.getInt(getDBAreaFaultTimeStat, areaCode, 0));
        }
        areaDeviceFaultTimeStat.addBarSeriesData(areaFaultTimeStat);
        return areaDeviceFaultTimeStat;
    }

    /**
     * doRepairWorkStat
     *
     * @param param 查询参数
     * @return
     */
    @Override
    public BarChartOptionModel doRepairWorkStat(Map<String, Object> param) {
        BarChartOptionModel<Integer> repairWorkStatModel = new BarChartOptionModel<>();
        BarChartSeriesModel<Integer> repairModel = new BarChartSeriesModel<>();
        BarChartSeriesModel<Integer> pmModel = new BarChartSeriesModel<>();
        // 移除空参数
        com.sugon.utils.MapUtil.removeEmptyValue(param);
        // 获取维修工作量统计
        List<WorkloadStatDTO> repairWorkStatList = devMaintenRepairDao.doRepairWorkStat(param);
        // 判断统计数据是否为空
        if (CollectionUtil.isNotEmpty(repairWorkStatList)) {
            Map<String, List<WorkloadStatDTO>> group = repairWorkStatList.stream().collect(Collectors.groupingBy(WorkloadStatDTO::getNickName));
            group.forEach((wxg, wxgWorkloadList) -> {
                repairModel.add(wxgWorkloadList.stream().filter(workload -> "REPAIR".equals(workload.getWorkType())).map(WorkloadStatDTO::getDuration).reduce(0, (a, b) -> a + b));
                pmModel.add(wxgWorkloadList.stream().filter(workload -> "PM".equals(workload.getWorkType())).map(WorkloadStatDTO::getDuration).reduce(0, (a, b) -> a + b));
                repairWorkStatModel.addXAxisData(wxg);
            });
        }
        repairWorkStatModel.addBarSeriesData(repairModel);
        repairWorkStatModel.addBarSeriesData(pmModel);
        return repairWorkStatModel;
    }

    /**
     * 获取数据库中区域设备故障次数统计信息
     */
    private Map<String, Integer> getDBAreaFaultTimeStat(String deptId, String month, String column) {
        Map<String, Integer> map = new TreeMap<>();
        // 获取区域设备故障次数数据
        List<Map<String, Object>> areaFaultTimeStatList = devMaintenRepairDao.statAreaDevFaultTime(deptId, month, column);
        // 判断数据是否为空
        if (CollectionUtil.isNotEmpty(areaFaultTimeStatList)) {
            for (Map<String, Object> areaFaultTimeStat : areaFaultTimeStatList) {
                map.put(MapUtil.getStr(areaFaultTimeStat, "DCODE"), MapUtil.getInt(areaFaultTimeStat, "TIME"));
            }
        }
        return map;
    }

    /**
     * 获取故障工单各时间段平均统计
     * 从接单、维修、效果确认三个维度 yxd
     *
     * @param param 查询参数
     * @return
     */
    @Override
    public PieChartOptionDataVO getWorkExecuteAvgStat(Map<String, Object> param) {
        PieChartOptionDataVO workExecuteAvgStat = new PieChartOptionDataVO();
        // 获取设备故障处理时长数据
        List<Map<String, Object>> durationStatList = devMaintenWorkDao.getFaultHandleDurationStat(param);
        Map<String, Object> durationStat = null;
        // 判断故障处理时长数据是否为空
        if (CollectionUtil.isNotEmpty(durationStatList)) {
            durationStat = durationStatList.get(0);
        }
        FaultHandleTime[] faultHandleTimes = FaultHandleTime.values();
        for (FaultHandleTime faultHandleTime : faultHandleTimes) {
            workExecuteAvgStat.addLegendData(faultHandleTime.getDesc());
            workExecuteAvgStat.addSeriesData(new PieChartSeriesDataItemVO(faultHandleTime.getDesc(), com.sugon.utils.MapUtil.getInt(durationStat, faultHandleTime.name(), 0)));
        }
        return workExecuteAvgStat;
    }

    /**
     * loadDevRepairTicketStat
     *
     * @param statType 统计类别 WEEKLY,MONTHLY
     * @return
     */
    @Override
    public PieChartOptionDataVO loadDevRepairTicketStat(String statType, String workshopId) {
        PieChartOptionDataVO pieChartOptionData = new PieChartOptionDataVO();
        // 获取设备
        DevRepairTicketStatusEnum[] devRepairTicketStatusEnums = DevRepairTicketStatusEnum.values();
        // 获取本周或者本月的不同状态下的工单数统计
        Map<String, String> queryParam = getStatDateRange(statType);
        // 拼接车间ID
        if (StrUtil.isNotEmpty(workshopId)) {
            queryParam.put("workshop", workshopId);
        }
        List<Map<String, Object>> statDataMapList = devMaintenWorkDao.doDevRepairTicketStatusNumStat(queryParam);
        // 整理数据
        Map<Integer, Integer> statData = handleStatDataMapList(statDataMapList);
        for (DevRepairTicketStatusEnum statusEnum : devRepairTicketStatusEnums) {
            pieChartOptionData.addSeriesData(new PieChartSeriesDataItemVO(statusEnum.getDesc(), com.sugon.modules.utils.MapUtil.getInt(statData, statusEnum.getValue(), 0)));
        }
        return pieChartOptionData;
    }

    /**
     * loadDevMaintenanceTicketStat
     *
     * @param statType 统计类别 WEEKLY,MONTHLY
     * @return
     */
    @Override
    public PieChartOptionDataVO loadDevMaintenanceTicketStat(String statType, String workshopId) {
        PieChartOptionDataVO pieChartOptionData = new PieChartOptionDataVO();
        // 获取设备
        DevMaintenanceTicketStatusEnum[] devMaintenanceTicketStatusEnums = DevMaintenanceTicketStatusEnum.values();
        // 获取本周或者本月的不同状态下的工单数统计
        Map<String, String> queryParam = getStatDateRange(statType);
        // 拼接车间ID
        if (StrUtil.isNotEmpty(workshopId)) {
            queryParam.put("workshop", workshopId);
        }
        List<Map<String, Object>> statDataMapList = devMaintenanceTicketDao.doDevMaintenanceTicketStatusNumStat(queryParam);
        // 整理数据
        Map<Integer, Integer> statData = handleStatDataMapList(statDataMapList);
        for (DevMaintenanceTicketStatusEnum statusEnum : devMaintenanceTicketStatusEnums) {
            pieChartOptionData.addSeriesData(new PieChartSeriesDataItemVO(statusEnum.getDesc(), com.sugon.modules.utils.MapUtil.getInt(statData, statusEnum.getValue(), 0)));
        }
        return pieChartOptionData;
    }

    /**
     * 将从数据库中查询出来的值 -> {1:22,2:1}
     * 以状态为键，工单数为值的map，便于后面使用
     *
     * @param statDataMapList
     * @return
     */
    Map<Integer, Integer> handleStatDataMapList(List<Map<String, Object>> statDataMapList) {
        Map<Integer, Integer> statData = new HashMap<>();
        if (CollectionUtil.isNotEmpty(statDataMapList)) {
            for (Map<String, Object> statDataMap : statDataMapList) {
                statData.put(MapUtil.getInt(statDataMap, "STATUS"), MapUtil.getInt(statDataMap, "TIMES"));
            }
        }
        return statData;
    }

    /**
     * 返回本周或本月的起始时间段
     *
     * @param statType 本周还是本月
     * @return
     */
    private Map<String, String> getStatDateRange(String statType) {
        Map<String, String> statDateRange = new HashMap<>();
        DateTime today = DateUtil.date();
        if ("WEEKLY".equals(statType)) {
            statDateRange.put("statStartDate", DateUtil.formatDateTime(DateUtil.beginOfWeek(today)));
            statDateRange.put("statEndDate", DateUtil.formatDateTime(DateUtil.endOfWeek(today)));
        } else if ("MONTHLY".equals(statType)) {
            statDateRange.put("statStartDate", DateUtil.formatDateTime(DateUtil.beginOfMonth(today)));
            statDateRange.put("statEndDate", DateUtil.formatDateTime(DateUtil.endOfMonth(today)));
        }
        return statDateRange;
    }

}
